package edu.indiana.d2i.vmm;

import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.indiana.d2i.vmm.cloud.OpenStackCloud;
import edu.indiana.d2i.vmm.job.SigiriHTRCJobFIFOScheduler;
import edu.indiana.d2i.vmm.job.SigiriHTRCJobInProgress;
import edu.indiana.d2i.vmm.policy.DynamicPoolPolicy;
import edu.indiana.d2i.vmm.policy.ShortRunVMMgrPolicy;
import edu.indiana.d2i.vmm.policy.SoftwareConstraintMgr;
import edu.indiana.d2i.vmm.policy.VMManagementPolicy;
import edu.indiana.extreme.sigiri.util.ConnectionManager;
import edu.indiana.extreme.sigiri.util.Constants;

public class SigiriHTRCJobTracker {
	private int jobSubmissionThreadInterval;
	private int jobStatusCheckerThreadInterval;
	private int jobSubmissionThreadCount;
	
	private static final Log logger = LogFactory.getLog(SigiriHTRCJobTracker.class);
	private Properties props;
	private ConnectionManager cpm;
	private SigiriHTRCJobScheduler scheduler;
	private SigiriHTRCConfiguration config;
	
	private ExecutorService executor = null;
	private List<SigiriHTRCJobInProgress> runningJobs = new LinkedList<SigiriHTRCJobInProgress>();
	
	// bottle neck here!!!
	class SigiriHTRCJobStatusChecker extends TimerTask {	
		private Stack<SigiriHTRCJobInProgress> removeItems = new Stack<SigiriHTRCJobInProgress>();
		@Override
		public void run() {
			for (int i = 0; i < runningJobs.size(); i++) {
				SigiriHTRCJobInProgress jobInProgress = runningJobs.get(i);
				boolean keepUpdate = jobInProgress.jobManager.updateJobStatus();
				if (!keepUpdate) removeItems.push(jobInProgress);
			}
			while (!removeItems.isEmpty()) runningJobs.remove(removeItems.pop()); 
		}
	}
	
	private void initialize() throws Exception {
		InputStream inStream = getClass().getClassLoader().getResourceAsStream(
				"sigiri.properties");
		props = new Properties();
		props.load(inStream);
		final String driverName = props
				.getProperty(Constants.SigiriProperties.DB_DRIVER_NAME);
		final String jdbcURL = props
				.getProperty(Constants.SigiriProperties.DB_URL);
		final String username = props
				.getProperty(Constants.SigiriProperties.DB_USERNAME);
		final String password = props
				.getProperty(Constants.SigiriProperties.DB_PWD);
		final String maxConns = props
				.getProperty(Constants.SigiriProperties.DB_MAX_CONNS);
		final String minConns = props
				.getProperty(Constants.SigiriProperties.DB_MIN_CONNS);
		final boolean enableConnectionPooling = "true".equalsIgnoreCase(props
				.getProperty(Constants.SigiriProperties.ENABLE_CONN_POOL));
		final boolean enableHighPerformanceMode = "true"
				.equalsIgnoreCase(props
						.getProperty(Constants.SigiriProperties.ENABLE_HIGH_PERFORMANCE_MODE));
		jobSubmissionThreadInterval = Integer
				.parseInt(props
						.getProperty(Constants.SigiriProperties.JOB_SUBMISSION_INTERVAL));
		jobStatusCheckerThreadInterval = Integer
				.parseInt(props
						.getProperty(Constants.SigiriProperties.JOB_STATUS_CHECKING_INTERVAL));
		jobSubmissionThreadCount = Integer.parseInt(props
				.getProperty(Constants.SigiriProperties.JOB_SUBMISSION_THREAD_COUNT));
		
		cpm = ConnectionManager.getInstance(driverName, jdbcURL, username,
				password, minConns, maxConns, enableConnectionPooling,
				enableHighPerformanceMode);
		if (cpm == null) throw new RuntimeException("Database connection manager is not initialized. System start failed."); 
		
		config = new SigiriHTRCConfiguration();
		executor = Executors.newCachedThreadPool();
		logger.info("Database connection created successfully");
	}
	
	public void start(String resourceName, String jobManagerName) throws Exception {		
		initialize();
	
		VMManagementPolicy policy = new ShortRunVMMgrPolicy(new SoftwareConstraintMgr(), 
				new OpenStackCloud(config));
		scheduler = new SigiriHTRCJobFIFOScheduler(policy, cpm, config, resourceName, jobManagerName, jobSubmissionThreadCount);
//		scheduler = new SigiriHTRCJobFIFOScheduler(new DynamicPoolPolicy((ShortRunVMMgrPolicy)policy), cpm, resourceName, jobManagerName, jobSubmissionThreadCount);
		
		logger.info("Starting job status checker ...");
		Timer jobStatusCheckertimer = new Timer();
		jobStatusCheckertimer.scheduleAtFixedRate(new SigiriHTRCJobStatusChecker(), 5000,
				jobStatusCheckerThreadInterval * 1000);

		logger.info("Starting Job tracker ...");
		while (true) {
			List<SigiriHTRCJobInProgress> joblist = scheduler.scheduleJob();
			if (joblist != null) {
				for (SigiriHTRCJobInProgress jobInProgress : joblist) {
					SigiriHTRCJobManager jobManager = jobInProgress.jobManager;
					jobManager.setJobManagerId("");
					
					runningJobs.add(jobInProgress);
					executor.execute(jobManager);
				}
			}
			
			Thread.sleep(1000 * jobSubmissionThreadInterval);
		}
	}

	public static void main(String[] args) {
		try {
			new SigiriHTRCJobTracker().start("Quarry", "");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
